const multer = require('multer');
const path = require('path');
const fs = require('fs').promises;
const crypto = require('crypto');
const { logger } = require('./logger');

/**
 * 文件上传工具类
 * 处理各种文件上传需求
 */
class FileUploadUtil {
  /**
   * 生成安全的文件名
   * @param {string} originalName - 原始文件名
   * @param {string} prefix - 文件名前缀
   * @returns {string} 安全的文件名
   */
  static generateSafeFileName(originalName, prefix = '') {
    const ext = path.extname(originalName).toLowerCase();
    const timestamp = Date.now();
    const randomString = crypto.randomBytes(8).toString('hex');
    return `${prefix}${timestamp}_${randomString}${ext}`;
  }

  /**
   * 确保目录存在
   * @param {string} dirPath - 目录路径
   */
  static async ensureDirectoryExists(dirPath) {
    try {
      await fs.access(dirPath);
    } catch (error) {
      if (error.code === 'ENOENT') {
        await fs.mkdir(dirPath, { recursive: true });
      } else {
        throw error;
      }
    }
  }

  /**
   * 删除文件
   * @param {string} filePath - 文件路径
   */
  static async deleteFile(filePath) {
    try {
      await fs.unlink(filePath);
    } catch (error) {
      if (error.code !== 'ENOENT') {
        logger.warn('删除文件失败:', error.message);
      }
    }
  }

  /**
   * 获取文件大小（字节）
   * @param {string} filePath - 文件路径
   * @returns {Promise<number>} 文件大小
   */
  static async getFileSize(filePath) {
    try {
      const stats = await fs.stat(filePath);
      return stats.size;
    } catch (error) {
      return 0;
    }
  }

  /**
   * 验证文件类型
   * @param {string} mimetype - MIME类型
   * @param {string[]} allowedTypes - 允许的类型列表
   * @returns {boolean} 是否允许
   */
  static isAllowedFileType(mimetype, allowedTypes) {
    return allowedTypes.some(type => {
      if (type.endsWith('/*')) {
        return mimetype.startsWith(type.slice(0, -1));
      }
      return mimetype === type;
    });
  }

  /**
   * 创建头像上传配置
   * @returns {multer.Multer} multer实例
   */
  static createAvatarUpload() {
    return multer({
      storage: multer.memoryStorage(),
      limits: {
        fileSize: 5 * 1024 * 1024, // 5MB
        files: 1
      },
      fileFilter: (req, file, cb) => {
        const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
        if (this.isAllowedFileType(file.mimetype, allowedTypes)) {
          cb(null, true);
        } else {
          cb(new Error('只允许上传 JPEG, PNG, GIF, WebP 格式的图片'), false);
        }
      }
    });
  }

  /**
   * 创建菜单图片上传配置
   * @returns {multer.Multer} multer实例
   */
  static createMenuImageUpload() {
    return multer({
      storage: multer.memoryStorage(),
      limits: {
        fileSize: 10 * 1024 * 1024, // 10MB
        files: 5 // 最多5张图片
      },
      fileFilter: (req, file, cb) => {
        const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
        if (this.isAllowedFileType(file.mimetype, allowedTypes)) {
          cb(null, true);
        } else {
          cb(new Error('只允许上传 JPEG, PNG, WebP 格式的图片'), false);
        }
      }
    });
  }

  /**
   * 创建文档上传配置
   * @returns {multer.Multer} multer实例
   */
  static createDocumentUpload() {
    return multer({
      storage: multer.memoryStorage(),
      limits: {
        fileSize: 20 * 1024 * 1024, // 20MB
        files: 1
      },
      fileFilter: (req, file, cb) => {
        const allowedTypes = [
          'application/pdf',
          'application/msword',
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
          'application/vnd.ms-excel',
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
          'text/plain',
          'text/csv'
        ];
        if (this.isAllowedFileType(file.mimetype, allowedTypes)) {
          cb(null, true);
        } else {
          cb(new Error('只允许上传 PDF, Word, Excel, TXT, CSV 格式的文档'), false);
        }
      }
    });
  }

  /**
   * 保存上传的文件
   * @param {Buffer} buffer - 文件缓冲区
   * @param {string} fileName - 文件名
   * @param {string} subDir - 子目录名
   * @returns {Promise<string>} 文件相对路径
   */
  static async saveUploadedFile(buffer, fileName, subDir = '') {
    const uploadDir = process.env.UPLOAD_PATH || 'uploads';
    const targetDir = subDir ? path.join(uploadDir, subDir) : uploadDir;
    
    // 确保目录存在
    await this.ensureDirectoryExists(targetDir);
    
    // 保存文件
    const filePath = path.join(targetDir, fileName);
    await fs.writeFile(filePath, buffer);
    
    // 返回相对路径（用于存储到数据库）
    return subDir ? `/${subDir}/${fileName}` : `/${fileName}`;
  }

  /**
   * 处理头像上传
   * @param {Express.Multer.File} file - 上传的文件
   * @param {string} userId - 用户ID
   * @returns {Promise<string>} 头像URL
   */
  static async processAvatarUpload(file, userId) {
    if (!file) {
      throw new Error('没有上传文件');
    }

    const fileName = this.generateSafeFileName(file.originalname, `avatar_${userId}_`);
    const relativePath = await this.saveUploadedFile(file.buffer, fileName, 'avatars');
    
    return `/uploads${relativePath}`;
  }

  /**
   * 处理菜单图片上传
   * @param {Express.Multer.File[]} files - 上传的文件数组
   * @param {string} menuId - 菜单ID
   * @returns {Promise<string[]>} 图片URL数组
   */
  static async processMenuImagesUpload(files, menuId) {
    if (!files || files.length === 0) {
      throw new Error('没有上传文件');
    }

    const imageUrls = [];
    
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const fileName = this.generateSafeFileName(file.originalname, `menu_${menuId}_${i + 1}_`);
      const relativePath = await this.saveUploadedFile(file.buffer, fileName, 'menu-images');
      imageUrls.push(`/uploads${relativePath}`);
    }
    
    return imageUrls;
  }

  /**
   * 处理文档上传
   * @param {Express.Multer.File} file - 上传的文件
   * @param {string} category - 文档分类
   * @returns {Promise<Object>} 文档信息
   */
  static async processDocumentUpload(file, category = 'general') {
    if (!file) {
      throw new Error('没有上传文件');
    }

    const fileName = this.generateSafeFileName(file.originalname, `doc_${category}_`);
    const relativePath = await this.saveUploadedFile(file.buffer, fileName, 'documents');
    
    return {
      url: `/uploads${relativePath}`,
      original_name: file.originalname,
      file_name: fileName,
      mime_type: file.mimetype,
      size: file.size
    };
  }

  /**
   * 清理过期的临时文件
   * @param {number} maxAge - 最大年龄（毫秒）
   */
  static async cleanupTempFiles(maxAge = 24 * 60 * 60 * 1000) { // 默认24小时
    try {
      const tempDir = path.join(process.env.UPLOAD_PATH || 'uploads', 'temp');
      
      try {
        await fs.access(tempDir);
      } catch (error) {
        return; // 目录不存在，无需清理
      }
      
      const files = await fs.readdir(tempDir);
      const now = Date.now();
      
      for (const file of files) {
        const filePath = path.join(tempDir, file);
        const stats = await fs.stat(filePath);
        
        if (now - stats.mtime.getTime() > maxAge) {
          await this.deleteFile(filePath);
          logger.info(`清理过期临时文件: ${file}`);
        }
      }
    } catch (error) {
      logger.error('清理临时文件失败:', error);
    }
  }

  /**
   * 获取文件的MIME类型
   * @param {string} filePath - 文件路径
   * @returns {string} MIME类型
   */
  static getMimeTypeFromExtension(filePath) {
    const ext = path.extname(filePath).toLowerCase();
    const mimeTypes = {
      '.jpg': 'image/jpeg',
      '.jpeg': 'image/jpeg',
      '.png': 'image/png',
      '.gif': 'image/gif',
      '.webp': 'image/webp',
      '.pdf': 'application/pdf',
      '.doc': 'application/msword',
      '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      '.xls': 'application/vnd.ms-excel',
      '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      '.txt': 'text/plain',
      '.csv': 'text/csv'
    };
    
    return mimeTypes[ext] || 'application/octet-stream';
  }

  /**
   * 验证图片尺寸
   * @param {Buffer} buffer - 图片缓冲区
   * @param {Object} constraints - 尺寸约束 { minWidth, maxWidth, minHeight, maxHeight }
   * @returns {Promise<boolean>} 是否符合要求
   */
  static async validateImageDimensions(buffer, constraints = {}) {
    // 这里可以使用 sharp 或其他图片处理库来获取图片尺寸
    // 暂时返回 true，实际项目中需要实现具体的尺寸验证逻辑
    return true;
  }
}

module.exports = FileUploadUtil;